﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Collections;
using OpenExpressApp.Types;
using OpenExpressApp.Module.WPF.Editors;
using OpenExpressApp.MetaModel;
using Itenso.Windows.Input;
using OpenExpressApp.Editors;
using System.Windows.Media;
using System.Windows.Input;
using System.ComponentModel;
using System.Timers;
using System.Windows.Threading;
using OpenExpressApp.WPF.Controls;

namespace OpenExpressApp.Module.WPF.Controls
{
    /// <summary>
    /// 这是一个使用DataGrid为下拉内容的下拉控件（ComboBox）。
    /// 
    /// 继承ComboBox。
    /// 使用Resources/ComboDataGrid.xaml作为模板。
    /// 使用一个临时的ListObjectView来生成DataGird，并在内部把它们的事件整合进来。
    /// </summary>
    [TemplatePart(Name = "PART_DropDownPanel", Type = typeof(DockPanel))]
    [TemplatePart(Name = "PART_ButtonPanel", Type = typeof(DockPanel))]
    public class ComboDataGrid : System.Windows.Controls.ComboBox
    {
        /// <summary>
        /// 定时器延迟时间
        /// </summary>
        private const int DEFAULT_DELAY = 800;

        static ComboDataGrid()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ComboDataGrid),
                new FrameworkPropertyMetadata(typeof(ComboDataGrid)));
        }

        private PropertyEditor _propertyEditor;

        /// <summary>
        /// 下拉的弹出框使用的是一个临时的ListObjectView来生成动态Grid。
        /// </summary>
        private IListObjectView _listObjectView;

        /// <summary>
        /// 控制输入定时器
        /// </summary>
        private Timer _interval;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="propertyEditor">为这个属性生成的下拉框。</param>
        public ComboDataGrid(PropertyEditor propertyEditor)
        {
            if (propertyEditor == null) throw new ArgumentNullException("propertyEditor");

            this._propertyEditor = propertyEditor;

            var lookupType = propertyEditor.PropertyInfo.LookupAttribute.LookupType;

            this._listObjectView = ViewFactory.Instance.CreateListView(lookupType);
            this._listObjectView.RegionType = RegionType.LookupList;
            this._listObjectView.SelectedItemChanged += _listObjectView_SelectedItemChanged;
            ////弹出的DataGrid是不能编辑的，见：http://ipm.grandsoft.com.cn/issues/114217
            this._listObjectView.IsReadOnly = true;

            //构造Timer
            if (DesignerProperties.GetIsInDesignMode(this) == false)
            {
                this._interval = new Timer(DEFAULT_DELAY);
                this._interval.AutoReset = true;
                this._interval.Elapsed += new ElapsedEventHandler(_interval_Elapsed);
            }
        }

        /// <summary>
        /// 控件选中文本
        /// </summary>
        public string SelectedText
        {
            get
            {
                if (this.SelectedIndex == -1)
                {
                    return string.Empty;
                }
                return this.SelectedItem.GetType().GetProperty(this.DisplayMemberPath)
                    .GetValue(this.SelectedItem, null).ToString();
            }
        }

        /// <summary>
        /// 在设置时，给View定位。
        /// </summary>
        public new object SelectedItem
        {
            get
            {
                return base.SelectedItem;
            }
            set
            {
                if (base.SelectedItem != value)
                {
                    base.SelectedItem = value;

                    //给View控件定位
                    this._listObjectView.SelectedItemChanged -= _listObjectView_SelectedItemChanged;
                    this._listObjectView.CurrentObject = base.SelectedItem;
                    this._listObjectView.SelectedItemChanged += _listObjectView_SelectedItemChanged;
                }
            }
        }

        /// <summary>
        /// 获取控件的编辑区域
        /// </summary>
        private TextBox EditableTextBox
        {
            get
            {
                return base.GetTemplateChild("PART_EditableTextBox") as TextBox;
            }
        }

        /// <summary>
        /// 自动完成事件
        /// </summary>
        public event EventHandler<AutoCompleteArgs> PatternChanged;

        #region 界面生成

        /// <summary>
        /// 在应用模板时，在模板中生成一些动态控件。
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.CreateButtons();

            this.CreateTextBox();

            this.CreateDataGrid();
        }

        /// <summary>
        /// 生成一个清空数据的按钮
        /// </summary>
        private void CreateButtons()
        {
            Panel buttonPanel = this.Template.FindName("PART_ButtonPanel", this) as Panel;

            Button btnClearValue = new Button();
            btnClearValue.SetValue(DockPanel.DockProperty, Dock.Right);
            btnClearValue.CommandParameter = this._propertyEditor;
            var command = CommandRepository.NewCommand(CommandNames.ClearLookupPropertyValue);
            ButtonCommand.SetCommand(btnClearValue, command);

            buttonPanel.Children.Add(btnClearValue);
        }

        private void CreateTextBox()
        {
            var txtBox = this.EditableTextBox;
            if (txtBox != null)
            {
                txtBox.PreviewKeyDown += new KeyEventHandler(EditableTextBox_PreviewKeyDown);
                txtBox.TextChanged += new TextChangedEventHandler(EditableTextBox_TextChanged);
            }
        }

        /// <summary>
        /// 生成用于显示弹出数据的一个DataGrid
        /// </summary>
        private void CreateDataGrid()
        {
            Panel dropDownPanel = this.Template.FindName("PART_DropDownPanel", this) as Panel;
            var listControl = this._listObjectView.Control as FrameworkElement;
            dropDownPanel.Children.Add(listControl);
        }

        #endregion

        /// <summary>
        /// 如果Lookup是树形结构，获取RootPId的属性名，可以只显示部分树
        /// 根据rootPid绑定数据
        /// </summary>
        /// <param name="rootPid">
        /// 如果这个值不是null，则这个值表示绑定的所有根节点的父id。
        /// </param>
        public void BindData(object rootPid)
        {
            if (this._listObjectView.IsShowingTree)
            {
                this._listObjectView.BindData(rootPid);
            }
        }

        /// <summary>
        /// ComboBox数据源改变时，ListObjectView中的控件也要改变数据。
        /// </summary>
        /// <param name="oldValue"></param>
        /// <param name="newValue"></param>
        protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
        {
            base.OnItemsSourceChanged(oldValue, newValue);

            this._listObjectView.SelectedItemChanged -= this._listObjectView_SelectedItemChanged;
            this._listObjectView.Data = newValue as IList;
            this._listObjectView.SelectedItemChanged += this._listObjectView_SelectedItemChanged;
        }

        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);

            this._isKeyEvent = false;
            //this.IsDropDownOpen = false;

            if (this.SelectedIndex >= 0)
            {
                this.Text = this.SelectedText;
            }

            this._interval.Close();

            try
            {
                this.EditableTextBox.CaretIndex = 0;
            }
            catch
            {
                //此异常暂时不做处理
            }
        }

        /// <summary>
        /// 在ListObjectView选择某数据时，把本ComboBox控件的SelectedItem值设置正确。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _listObjectView_SelectedItemChanged(object sender, SelectedItemChangedEventArgs e)
        {
            //设置基类的SelectedItem
            base.SelectedItem = e.NewItem;

            //if (this._listObjectView.IsShowingTree)
            //{
            this.IsDropDownOpen = false;
            //}

            this._interval.Stop();
        }

        private void _interval_Elapsed(object sender, ElapsedEventArgs e)
        {
            this._isKeyEvent = false;
            this._interval.Stop();
            //输入后异步触发事件
            this.Dispatcher.BeginInvoke((Action)delegate
            {
                this.IsDropDownOpen = true;
                if (this.PatternChanged != null)
                {
                    var args = new AutoCompleteArgs(this.Text);

                    this.PatternChanged(this, args);

                    // 绑定新的数据源
                    this.ItemsSource = args.DataSource;
                    this.Text = args.Pattern;
                    this.EditableTextBox.CaretIndex = args.Pattern.Length;
                }
            }, DispatcherPriority.ApplicationIdle);
        }

        /// <summary>
        /// 判断是否是用户正在输入
        /// </summary>
        private bool _isKeyEvent;

        private void EditableTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            this._isKeyEvent = true;
        }

        /// <summary>
        /// 如果是用户开始输入，则开始计时。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (this._isKeyEvent)
            {
                //ResetTimer
                this._interval.Stop();
                this._interval.Start();
            }
        }

        #region public class AutoCompleteArgs

        /// <summary>
        /// 自动完成事件参数
        /// </summary>
        public class AutoCompleteArgs : EventArgs
        {
            private string _pattern;
            /// <summary>
            /// The current pattern in the auto complete
            /// </summary>
            public string Pattern
            {
                get
                {
                    return this._pattern;
                }
            }

            private IEnumerable _dataSource;
            /// <summary>
            /// Used to the the new datasource for the autocomplete
            /// </summary>
            public IEnumerable DataSource
            {
                get
                {
                    return this._dataSource;
                }
                set
                {
                    this._dataSource = value;
                }
            }

            public AutoCompleteArgs(string Pattern)
            {
                this._pattern = Pattern;
            }
        }

        #endregion
    }
}